package com.xhwl.centiotdata.suppliersystem.bosiny;

import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xhwl.centiotdata.constant.BosinyConstant;
import com.xhwl.centiotdata.pojo.dto.pedestrian.PedestrianIntegrationConfigDTO;
import com.xhwl.centiotdata.utils.RedisUtils;
import com.xhwl.common.exception.BusinessException;
import com.xhwl.common.utils.Md5Util;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * Falcon.cao @Copyright (C), 2022, 兴海物联
 * Date: 2022/6/10 17:00
 * Description: 包信息
 */
@Service
public class GeneralBosinyHandler {
    private static final Logger log = LoggerFactory.getLogger(GeneralBosinyHandler.class);

    @Autowired
    private RedisUtils redisUtils;

    /**
     * 执行请求
     *
     * @param data   请求参数
     * @param config 系统配置
     */
    public JSONObject execute(PedestrianIntegrationConfigDTO config, JSONObject data, String name, String versions) {
        JSONObject params = new JSONObject();
        params.put(BosinyConstant.PARAM_NAME, name);
        params.put(BosinyConstant.PARAM_VERSIONS, versions);
        params.put(BosinyConstant.PARAM_AK, config.getAk());
        try {
            if (data != null) {
                params.put(BosinyConstant.PARAM_DATA, URLEncoder.encode(data.toJSONString(), "utf-8"));
            }
        } catch (Exception e) {
            log.error("请求体构建失败", e);
        }
        params.put(BosinyConstant.PARAM_TIMESTAMP, new SimpleDateFormat(BosinyConstant.FORMAT_DATETIME).format(new Date()));
        params.put(BosinyConstant.PARAM_FORMAT, "json");
        onFindingAccessToken(params, config);
        params.put(BosinyConstant.PARAM_SIGN, signature(params, config));

        String response = HttpRequest.post(config.getIpAndPort()).setConnectionTimeout(3000).setReadTimeout(20000)
                .body(JSON.toJSONString(params)).execute()
                .body();
        return JSON.parseObject(response);
    }

    /**
     * 获取鉴权参数
     *
     * @param config 系统配置
     */
    private void onFindingAccessToken(JSONObject request, PedestrianIntegrationConfigDTO config) {
        String token = (String) redisUtils.get(String.format(BosinyConstant.REDIS_KEY_TOKEN, config.getAk(), config.getSk()));
        String jwt = (String) redisUtils.get(String.format(BosinyConstant.REDIS_KEY_JWT, config.getAk(), config.getSk()));
        if (StringUtils.isNotBlank(token)) {
            request.put(BosinyConstant.PARAM_TOKEN, token);
        }
        if (StringUtils.isNotBlank(jwt)) {
            request.put(BosinyConstant.PARAM_JWT, jwt);
            return;
        }
        onGettingAccessToken(request, config);
    }

    private void onGettingAccessToken(JSONObject request, PedestrianIntegrationConfigDTO config) {
        long timestamp = System.currentTimeMillis();

        JSONObject data = new JSONObject();
        data.put(BosinyConstant.PARAM_LOGIN_NAME, config.getLoginName());
        data.put(BosinyConstant.PARAM_PASSWORD, config.getPassword());

        JSONObject params = new JSONObject();
        params.put(BosinyConstant.PARAM_NAME, BosinyConstant.NAME_LOGIN);
        params.put(BosinyConstant.PARAM_AK, config.getAk());
        try {
            params.put(BosinyConstant.PARAM_DATA, URLEncoder.encode(data.toJSONString(), "utf-8"));
        } catch (Exception e) {
            log.error("请求体构建失败", e);
        }
        params.put(BosinyConstant.PARAM_VERSIONS, "");
        params.put(BosinyConstant.PARAM_TIMESTAMP, new SimpleDateFormat(BosinyConstant.FORMAT_DATETIME).format(new Date()));
        params.put(BosinyConstant.PARAM_SIGN, signature(params, config));

        String response = HttpRequest.post(config.getIpAndPort()).setConnectionTimeout(3000).setReadTimeout(20000)
                .body(params.toJSONString()).execute()
                .body();
        log.info("登录博西尼：{}，耗时：{}，结果：{}", params.toJSONString(), (System.currentTimeMillis() - timestamp), response);

        JSONObject result = JSON.parseObject(response);
        if (!"0".equals(result.getString("code"))) {
            throw new BusinessException("登录博西尼系统失败：" + result.getString("msg"));
        }
        JSONObject json = result.getJSONObject("data");
        String jwt = json.getString("jwt");
        String token = json.getString("access_token");

        request.put(BosinyConstant.PARAM_JWT, jwt);
        request.put(BosinyConstant.PARAM_TOKEN, token);

        redisUtils.setWithMinute(String.format(BosinyConstant.REDIS_KEY_TOKEN, config.getAk(), config.getSk()), token, 100);
        redisUtils.setWithMinute(String.format(BosinyConstant.REDIS_KEY_JWT, config.getAk(), config.getSk()), jwt, 100);
    }

    /**
     * 获取请求加密认证
     *
     * @param params 请求参数
     * @param config 系统配置
     */
    private String signature(JSONObject params, PedestrianIntegrationConfigDTO config) {
        List<String> collections = new ArrayList<>(params.keySet());
        Collections.sort(collections);
        StringBuilder builder = new StringBuilder();
        for (String collect : collections) {
            builder.append(collect).append(params.get(collect));
        }
        String source = config.getSk() + builder.toString() + config.getSk();
        return Md5Util.encrypt(source).toUpperCase();
    }

}
